const vscode = require('vscode');
const path = require('path');
const fs = require('fs');
const util = require('../util');

/**
 * 查找文件定义的provider，匹配到了就return一个location，否则不做处理
 * 最终效果是，当按住Ctrl键时，如果return了一个location，字符串就会变成一个可以点击的链接，否则无任何效果
 * @param {*} document 
 * @param {*} position 
 * @param {*} token 
 */
function provideDefinition(document, position, token) {
    const fileName    = document.fileName;
    const workDir     = path.dirname(fileName);
    const word        = document.getText(document.getWordRangeAtPosition(position));
    const line        = document.lineAt(position);
    const projectPath = util.getProjectPath(document);

    util.log('====== provideDefinition 查找 ===========');
    util.log('fileName: ' + fileName);
    util.log('workDir: ' + workDir);
    util.log('word: ' + word);
    util.log('line: ' + line.text);
    util.log('projectPath: ' + projectPath);

    // 匹配 this.proxy.xxx(.xxx)，这里的匹配比较简单粗暴
    const result = /((^|=| )\w+\.proxy\.)(\w+?)(\.([\w$]+?))?($|\(| )/g.exec(line.text);
    if (!result) return;

    /* const window = {require};
    vm.createContext(window);
    vm.runInContext(`proxy = require('${rootPath}/${projectName}/config/proxy.js')`, window); */
    
    // 如果匹配到 this.proxy.xxx ，跳转到对应的proxy声明文件中去
    if(result[3] == word) {
        const matchStart = result.index + result[1].length;
        const matchEnd = matchStart + word.length;
        // 确认匹配的字符串就是当前光标所在的字符串
        if(position.character >= matchStart && position.character <= matchEnd) {
            const serviceName =  util.upperFirstLetter(word); // 首字母大写
            console.log(require.cache);
            const proxy = require(`${projectPath}/config/proxy.js`);
            const services = proxy.services.filter(item => !!item.api[serviceName]);
            util.log(services);
            if (services.length) {
                // 一般来说这种情况不存在
                if (services.length > 1) {
                    console.warn('匹配到多个services，默认进入第一个！');
                }
                const appname = services[0].appname;
                const destPath = `${projectPath}/config/proxy-cfg/${appname}.js`;
                // 这里是通过appname去查找文件，部分文件写法不规范，appname和文件名不相同，后续再考虑兼容
                if (!fs.existsSync(destPath)) {
                    util.error(`不存在如下文件：${destPath}`);
                    return;
                }
                // new vscode.Position(0, 0) 表示跳转到某个文件的第一行第一列
                const pos = util.findStrInFile(destPath, serviceName);
                util.addGoldLog('definition-proxy');
                return new vscode.Location(vscode.Uri.file(destPath), new vscode.Position(pos.row, pos.col));
            }
        }
    }
    // 如果匹配到 this.proxy.xxx.xxx，跳转到对应的app/proxy/xxx.js 文件中去
    else if(result[5] == word) {
        const matchStart = result.index + result[1].length + result[3].length;
        const matchEnd = matchStart + word.length;
        console.log(result.index, position.character, matchStart, matchEnd)
        // 确认匹配的字符串就是当前光标所在的字符串
        if(position.character >= matchStart && position.character <= matchEnd) {
            const fileName = util.upperFirstLetter(result[3]); // 首字母大写
            const filePath = `${projectPath}/app/proxy/${fileName}.js`;
            if(!fs.existsSync(filePath)) {
                console.warn('File not found: ' + filePath);
                return;
            }
            // 这里定位查找都是简单的字符串匹配，不包含词法语法分析
            // 方法名可能会包含$符号，如 get$7e761f1， 所以需要先对word进行特殊处理，$ 转 \\$
            const pos = util.findStrInFile(filePath, new RegExp(`${word.replace(/\$/g, '\\$')}\\([a-zA-Z, ]+?\\)\\s*?\\{`));
            util.addGoldLog('definition-proxy');
            return new vscode.Location(vscode.Uri.file(filePath), new vscode.Position(pos.row, pos.col));
        }
    }
}

module.exports = function(context) {
    // 注册如何实现跳转到定义
    context.subscriptions.push(vscode.languages.registerDefinitionProvider(['javascript', 'javascriptreact'], {
        provideDefinition
    }));
};